package util.exceptionTest;

import java.util.Optional;
import java.util.function.Function;

/**
 * @Author liw
 * @Date 2021/3/17 13:45
 * @Version 1.0
 */
public class Either<L, R> {

    // 异常
    private final L left;

    private final R right;

    private Either(L left, R right) {
        this.left = left;
        this.right = right;
    }

    static <T, R> Function<T, Either<Pair<Exception, T>, R>> liftWithValue(CheckedFunction<T, R> function) {
        return t -> {
            try {
                return Either.right(function.apply(t));
            } catch (Exception ex) {
                return Either.left(Pair.of(ex, t));
            }
        };
    }

    public static <T, R> Function<T, Either<Exception, R>> lift(CheckedFunction<T, R> function) {
        return t -> {
            try {
                return Either.right(function.apply(t));
            } catch (Exception ex) {
                return Either.left(ex);
            }
        };
    }

    private static <L, R> Either<L, R> left(L value) {
        return new Either<>(value, null);
    }

    private static <L, R> Either<L, R> right(R value) {
        return new Either<>(null, value);
    }

    public <T> Optional<T> mapLeft(Function<? super L, T> mapper) {
        if (isLeft()) {
            return Optional.of(mapper.apply(left));
        }
        return Optional.empty();
    }

    public <T> Optional<T> mapRight(Function<? super R, T> mapper) {
        if (isRight()) {
            return Optional.of(mapper.apply(right));
        }
        return Optional.empty();
    }

    @Override
    public String toString() {
        if (isLeft()) {
            return "Left(" + left + ")";
        }
        return "Right(" + right + ")";
    }

    Optional<L> getLeft() {
        return Optional.ofNullable(left);
    }

    Optional<R> getRight() {
        return Optional.ofNullable(right);
    }

    boolean isLeft() {
        return left != null;
    }

    boolean isRight() {
        return right != null;
    }


}
